package com.alibaba.citrus.cr.mn.order.center.facade.function.assemble.impl.salesorder;

import com.alibaba.citrus.cr.common.enums.GeneralStatusEnum;
import com.alibaba.citrus.cr.common.enums.ordercenter.OrderCategoryEnum;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.BizInventoryQueryAdapter;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.CargoZoneAdapter;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.dataobject.request.InventoryAvailableQtyQueryRequest;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.dataobject.request.LogisticWarehouseQueryRequest;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.dataobject.response.InventoryAvailableQtyQueryDTO;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.dataobject.response.ItemSearchAbilityDTO;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.dataobject.response.LogisticWarehouseQueryDTO;
import com.alibaba.citrus.cr.mn.order.center.facade.function.assemble.OrderBizAssemble;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.bcorder.model.dto.WarehouseInfo;
import com.epoch.app.mnordercenter.model.dto.SalesOrderAtomCreateLineRequest;
import com.epoch.app.mnordercenter.model.dto.SalesOrderBizCreateRequest;
import com.epoch.app.mnordercenter.orderbaserequest.OrderLineAtomCreateRequest;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author zhangxiaorui
 * @ClassName OrderBizAssembleOfStrategyCenter
 * @description: TODO
 * @date 2023/05/17 09:53
 * @version: 1.0
 */
@Service
@Order(3)
public class SalesOrderCreateBizAssembleOfInventoryCenter implements OrderBizAssemble<SalesOrderBizCreateRequest> {
    private static final Log log = Log.getLogger(SalesOrderCreateBizAssembleOfInventoryCenter.class);
    private static final String SAP_ORG_CODE = "sapOrgCode";

    @Resource
    private BizInventoryQueryAdapter bizInventoryQueryAdapter;
    @Resource
    private CargoZoneAdapter cargoZoneAdapter;

    @Override
    public Map<String, Object> query(SalesOrderBizCreateRequest exchangeOrderBizCreateRequest) {
        return query(Lists.newArrayList(exchangeOrderBizCreateRequest));
    }

    @Override
    public Map<String, Object> query(List<SalesOrderBizCreateRequest> exchangeOrderBizCreateRequests) {
        try {
            // Key：库存工厂Code+库存地点Code or 逻辑仓库Code
            Map<String, LogisticWarehouseQueryDTO> logisticWarehouseQueryMap = queryLogisticWarehouseInfoList(exchangeOrderBizCreateRequests);
            // 库存可用数量
            Map<String, InventoryAvailableQtyQueryDTO> inventoryAvailableQtyQueryMap =
                    queryInventoryAvailableQty(exchangeOrderBizCreateRequests, logisticWarehouseQueryMap);
            Map<String, Object> result = Maps.newHashMap();
            result.put(LOGISTIC_WAREHOUSE, logisticWarehouseQueryMap);
            result.put(INVENTORY_AVAILABLE_QTY, inventoryAvailableQtyQueryMap);
            log.info("销售订单商业能力库存中心数据组装结果 result={}", JSONObject.toJSONString(result));
            //逻辑仓针对一盘货订单需要设置F-B的销售组织编码
            if(OrderCategoryEnum.STOCK.getCode().equals(exchangeOrderBizCreateRequests.get(0).getOrderCategoryCode())){
                exchangeOrderBizCreateRequests.forEach(item->{
                    SalesOrderAtomCreateLineRequest orderDetail =item.getOrderDetails().get(0);
                    //按照现有逻辑查询
                    String warehouseKey = orderDetail.getShippingWarehouseCode();
                    if (StringUtils.isBlank(warehouseKey)) {
                        warehouseKey = String.format("%s_%s", orderDetail.getDeliveryFactoryCode(), orderDetail.getStockCode());
                    }
                    LogisticWarehouseQueryDTO logisticWarehouseQueryDTO = logisticWarehouseQueryMap.get(warehouseKey);
                    if(!Objects.isNull(logisticWarehouseQueryDTO)){
                        item.setGroupSalesOrganizationCode(logisticWarehouseQueryDTO.getFeature().get(SAP_ORG_CODE));
                    }

                });
            }
            return result;
        }catch (Exception e) {
            log.error("销售订单商业能力库存中心数据组装失败", e);
            throw new RuntimeException(e);
        }
    }

    @Override
    public Result<String> assemble(Map<String, Object> queryResponseMap, SalesOrderBizCreateRequest createRequest) {

        // Key：库存工厂Code+库存地点Code or 逻辑仓库Code
        Map<String, LogisticWarehouseQueryDTO> logisticWarehouseMap = getBizInfoMap(queryResponseMap, LOGISTIC_WAREHOUSE, LogisticWarehouseQueryDTO.class);
        // 库存可用数量
        Map<String, InventoryAvailableQtyQueryDTO> inventoryAvailableQtyMap = getBizInfoMap(queryResponseMap, INVENTORY_AVAILABLE_QTY, InventoryAvailableQtyQueryDTO.class);
        // 物料
        Map<String, ItemSearchAbilityDTO> scItemInfoMap = getBizInfoMap(queryResponseMap, SC_ITEM_INFO, ItemSearchAbilityDTO.class);

        // 如果是一盘货销售订单，过账仓存入B-b订单的features里面用于履约服务去查询
        if (OrderCategoryEnum.STOCK.getCode().equals(createRequest.getOrderCategoryCode())) {
            WarehouseInfo warehouseInfo = cargoZoneAdapter.searchCargoZone(createRequest.getGroupReceiveWarehouseCode());
            if (Objects.nonNull(warehouseInfo)) {
                Map<String, String> features = Maps.newHashMap();
                features.put("shippingWarehouseCode", warehouseInfo.getCode());
                features.put("shippingWarehouseName", warehouseInfo.getName());
                features.put("deliveryFactoryCode", warehouseInfo.getSapFactoryCode());
                features.put("stockCode", warehouseInfo.getWarehouseCode());
                createRequest.setFeatures(JSON.toJSONString(features));
            }
        }

        Map<String, String> salesQty4ProductMap = Maps.newConcurrentMap();
        for (SalesOrderAtomCreateLineRequest orderDetail : createRequest.getOrderDetails()) {

            // 发货仓信息回填，Key：库存工厂Code+库存地点Code or 逻辑仓库Code
            String warehouseKey = orderDetail.getShippingWarehouseCode();
            if (StringUtils.isBlank(warehouseKey)) {
                warehouseKey = String.format("%s_%s", orderDetail.getDeliveryFactoryCode(), orderDetail.getStockCode());
            }
            LogisticWarehouseQueryDTO logisticWarehouseQueryResponse = logisticWarehouseMap.get(warehouseKey);
            if (Objects.isNull(logisticWarehouseQueryResponse)) {
                return Result.fail(createRequest.getSourceOrderNo(), "OC-01-001-01-16-045", "仓库地点不存在");
            }
            if (!GeneralStatusEnum.YES.getCode().equals(logisticWarehouseQueryResponse.getStatus())) {
                return Result.fail(createRequest.getSourceOrderNo(), "OC-01-001-01-16-045", "仓库地点不存在");
            }
            orderDetail.setShippingWarehouseCode(logisticWarehouseQueryResponse.getCode());
            orderDetail.setShippingWarehouseName(logisticWarehouseQueryResponse.getName());
            orderDetail.setDeliveryFactoryCode(logisticWarehouseQueryResponse.getSapFactoryCode());
            orderDetail.setStockCode(logisticWarehouseQueryResponse.getWarehouseCode());


            // 物料信息
            ItemSearchAbilityDTO scItem = scItemInfoMap.get(orderDetail.getProductCode());
            if (Objects.isNull(scItem)) {
                return Result.fail(createRequest.getSourceOrderNo(), "OC-01-001-01-16-012", "物料编码不存在");
            }

            String inventoryAvailableQtyKey = logisticWarehouseQueryResponse.getId() + "_" + scItem.getScItemId();

            log.info("inventoryAvailableQtyKey={}, inventoryAvailableQtyMap={}", inventoryAvailableQtyKey, JSONObject.toJSONString(inventoryAvailableQtyMap));

            // 校验库存
            if (Objects.isNull(createRequest.getCheckStock()) || Boolean.TRUE.equals(createRequest.getCheckStock())) {
                // 库存可用数量
                InventoryAvailableQtyQueryDTO inventoryAvailableQty = inventoryAvailableQtyMap.get(inventoryAvailableQtyKey);

                // 当前行的库存可用量校验
                if (Objects.isNull(inventoryAvailableQty)) {
                    return Result.fail(createRequest.getSourceOrderNo(), "OC-01-001-01-16-046", "库存可用余量小于销售数量");
                }
                if (Objects.isNull(inventoryAvailableQty.getAvailableQuantity())) {
                    return Result.fail(createRequest.getSourceOrderNo(), "OC-01-001-01-16-046", "库存可用余量小于销售数量");
                }
                if (StringUtils.isBlank(orderDetail.getProductQuantity())) {
                    return Result.fail(createRequest.getSourceOrderNo(), "OC-01-001-01-15-001", "参数【销售数量】不能为空");
                }
                BigDecimal currAvailableQty = new BigDecimal(inventoryAvailableQty.getAvailableQuantity()).divide(new BigDecimal("1000"), 3, RoundingMode.HALF_UP);

                BigDecimal totalQuantity = calSalesTotalQuantity(inventoryAvailableQtyKey, salesQty4ProductMap, orderDetail);
                if (totalQuantity.compareTo(currAvailableQty) > 0) {
                    return Result.fail(createRequest.getSourceOrderNo(), "OC-01-001-01-16-046", "库存可用余量小于销售数量");
                }
            }
        }

        // 收货仓信息回填，Key：库存工厂Code+库存地点Code or 逻辑仓库Code
        if (StringUtils.isNotBlank(createRequest.getReceiveWarehouseCode()) || StringUtils.isNotBlank(createRequest.getReceiveFactoryCode())) {
            String receiveWarehouseKey = createRequest.getReceiveWarehouseCode();
            if (StringUtils.isBlank(receiveWarehouseKey)) {
                receiveWarehouseKey = String.format("%s_%s", createRequest.getReceiveFactoryCode(), createRequest.getReceiveStockCode());
            }
            LogisticWarehouseQueryDTO logisticWarehouseQueryResponse = logisticWarehouseMap.get(receiveWarehouseKey);
            if (Objects.isNull(logisticWarehouseQueryResponse)) {
                return Result.fail(createRequest.getSourceOrderNo(), "OC-01-001-01-16-045", "收货仓不存在");
            }
            if (!GeneralStatusEnum.YES.getCode().equals(logisticWarehouseQueryResponse.getStatus())) {
                return Result.fail(createRequest.getSourceOrderNo(), "OC-01-001-01-16-045", "收货仓不存在");
            }
            createRequest.setReceiveWarehouseCode(logisticWarehouseQueryResponse.getCode());
            createRequest.setReceiveWarehouseName(logisticWarehouseQueryResponse.getName());
            createRequest.setReceiveFactoryCode(logisticWarehouseQueryResponse.getSapFactoryCode());
            createRequest.setReceiveStockCode(logisticWarehouseQueryResponse.getWarehouseCode());
        }

        return Result.success(null);
    }

    private BigDecimal calSalesTotalQuantity(String key, Map<String, String> salesQty4ProductMap, SalesOrderAtomCreateLineRequest orderDetail) {
        String currSalesTotalQty = salesQty4ProductMap.getOrDefault(key, "0");
        BigDecimal currentSaleUnitQty = new BigDecimal(orderDetail.getProductQuantity()).divide(new BigDecimal(orderDetail.getUnitConversionRelationship()),3,RoundingMode.HALF_UP);
        BigDecimal addedQty = currentSaleUnitQty.add(new BigDecimal(currSalesTotalQty));
        salesQty4ProductMap.put(key, addedQty.toPlainString());
        return addedQty;
    }

    private Map<String, LogisticWarehouseQueryDTO> queryLogisticWarehouseInfoList(List<SalesOrderBizCreateRequest> salesOrderBizCreateRequests) {
        List<LogisticWarehouseQueryRequest> logisticWarehouseQueryRequests = Lists.newArrayList();
        Set<String> dupLogisticWarehouseCode = Sets.newHashSet();
        Set<String> dupAddressAndFactoryCode = Sets.newHashSet();
        for (SalesOrderBizCreateRequest createRequest : salesOrderBizCreateRequests) {
            //发货仓
            for (SalesOrderAtomCreateLineRequest orderDetail : createRequest.getOrderDetails()) {

                if(StringUtils.isNotBlank(orderDetail.getShippingWarehouseCode())) {
                    if(!dupLogisticWarehouseCode.contains(orderDetail.getShippingWarehouseCode())) {

                        LogisticWarehouseQueryRequest queryRequest = new LogisticWarehouseQueryRequest();
                        queryRequest.setLogicWarehouseCode(orderDetail.getShippingWarehouseCode());
                        logisticWarehouseQueryRequests.add(queryRequest);

                        dupLogisticWarehouseCode.add(orderDetail.getShippingWarehouseCode());
                    }
                } else if(StringUtils.isNotBlank(orderDetail.getDeliveryFactoryCode()) && StringUtils.isNotBlank(orderDetail.getStockCode())) {
                    if(!dupAddressAndFactoryCode.contains(String.format("%s_%s", orderDetail.getDeliveryFactoryCode(), orderDetail.getStockCode()))) {

                        LogisticWarehouseQueryRequest queryRequest = new LogisticWarehouseQueryRequest();
                        queryRequest.setFactoryCode(orderDetail.getDeliveryFactoryCode());
                        queryRequest.setStorageLocation(orderDetail.getStockCode());
                        logisticWarehouseQueryRequests.add(queryRequest);

                        dupAddressAndFactoryCode.add(String.format("%s_%s", orderDetail.getDeliveryFactoryCode(), orderDetail.getStockCode()));
                    }
                }
            }

            //收货仓
            if (StringUtils.isNotBlank(createRequest.getReceiveWarehouseCode())) {
                if (!dupLogisticWarehouseCode.contains(createRequest.getReceiveWarehouseCode())) {
                    // 收货仓
                    LogisticWarehouseQueryRequest queryRequest = new LogisticWarehouseQueryRequest();
                    queryRequest.setLogicWarehouseCode(createRequest.getReceiveWarehouseCode());
                    logisticWarehouseQueryRequests.add(queryRequest);

                    dupLogisticWarehouseCode.add(createRequest.getReceiveWarehouseCode());
                }
            } else if (StringUtils.isNotBlank(createRequest.getReceiveFactoryCode()) && StringUtils.isNotBlank(createRequest.getReceiveStockCode())) {
                if (!dupAddressAndFactoryCode.contains(String.format("%s_%s", createRequest.getReceiveFactoryCode(), createRequest.getReceiveStockCode()))) {

                    LogisticWarehouseQueryRequest queryRequest = new LogisticWarehouseQueryRequest();
                    queryRequest.setFactoryCode(createRequest.getReceiveFactoryCode());
                    queryRequest.setStorageLocation(createRequest.getReceiveStockCode());
                    logisticWarehouseQueryRequests.add(queryRequest);

                    dupAddressAndFactoryCode.add(String.format("%s_%s", createRequest.getReceiveFactoryCode(), createRequest.getReceiveStockCode()));
                }
            }
        }

        if(CollectionUtils.isEmpty(logisticWarehouseQueryRequests)) {
            return Maps.newHashMap();
        }

        List<LogisticWarehouseQueryDTO> listResult = cargoZoneAdapter.queryCargoZoneListByParam(logisticWarehouseQueryRequests);
        if(CollectionUtils.isEmpty(listResult)) {
            return Maps.newHashMap();
        }

        Map<String, LogisticWarehouseQueryDTO> logisticWarehouseQueryResponseMap = Maps.newHashMap();
        for (LogisticWarehouseQueryDTO logisticWarehouseQueryResponse : listResult) {
            String factoryStockCode = String.format("%s_%s", logisticWarehouseQueryResponse.getSapFactoryCode(), logisticWarehouseQueryResponse.getWarehouseCode());
            logisticWarehouseQueryResponseMap.put(factoryStockCode, logisticWarehouseQueryResponse);
            logisticWarehouseQueryResponseMap.put(logisticWarehouseQueryResponse.getCode(), logisticWarehouseQueryResponse);
        }

        return logisticWarehouseQueryResponseMap;
    }

    private Map<String, InventoryAvailableQtyQueryDTO> queryInventoryAvailableQty(List<SalesOrderBizCreateRequest> salesOrderBizCreateRequests, Map<String, LogisticWarehouseQueryDTO> logisticWarehouseQueryMap) {

        List<InventoryAvailableQtyQueryRequest> inventoryAvailableQtyQueryRequests = Lists.newArrayList();

        for (SalesOrderBizCreateRequest createRequest : salesOrderBizCreateRequests) {

            Map<String, List<SalesOrderAtomCreateLineRequest>> warehouseOfOrderLineList1 = createRequest.getOrderDetails()
                    .stream()
                    .filter(p -> StringUtils.isNotBlank(p.getShippingWarehouseCode()))
                    .collect(Collectors.groupingBy(OrderLineAtomCreateRequest::getShippingWarehouseCode));

            warehouseOfOrderLineList1.forEach((warehouseCode, orderLineList)->{
                List<String> productCodes = orderLineList.stream().map(OrderLineAtomCreateRequest::getProductCode).distinct().collect(Collectors.toList());

                InventoryAvailableQtyQueryRequest queryRequest = new InventoryAvailableQtyQueryRequest();
                queryRequest.setLogicWarehouseCode(warehouseCode);
                queryRequest.setGoodsCodeList(productCodes);

                inventoryAvailableQtyQueryRequests.add(queryRequest);
            });

            Map<String, List<SalesOrderAtomCreateLineRequest>> warehouseOfOrderLineList2 = createRequest.getOrderDetails()
                    .stream()
                    .filter(p -> StringUtils.isNotBlank(p.getDeliveryFactoryCode()) && StringUtils.isNotBlank(p.getStockCode()))
                    .collect(Collectors.groupingBy(p->String.format("%s_%s", p.getDeliveryFactoryCode(), p.getStockCode())));

            warehouseOfOrderLineList2.forEach((deliveryFactoryStockCode, orderLineList)->{

                LogisticWarehouseQueryDTO logisticWarehouseQueryDTO = logisticWarehouseQueryMap.get(deliveryFactoryStockCode);
                if(Objects.isNull(logisticWarehouseQueryDTO)) {
                    return;
                }
                List<String> productCodes = orderLineList.stream().map(OrderLineAtomCreateRequest::getProductCode).distinct().collect(Collectors.toList());

                InventoryAvailableQtyQueryRequest queryRequest = new InventoryAvailableQtyQueryRequest();
                queryRequest.setLogicWarehouseCode(logisticWarehouseQueryDTO.getCode());
                queryRequest.setGoodsCodeList(productCodes);

                inventoryAvailableQtyQueryRequests.add(queryRequest);
            });
        }
        if(CollectionUtils.isEmpty(inventoryAvailableQtyQueryRequests)) {
            return Maps.newHashMap();
        }

        List<InventoryAvailableQtyQueryDTO> inventoryAvailableQtyList =
                bizInventoryQueryAdapter.queryInventoryAvailableQty(inventoryAvailableQtyQueryRequests);

        if(CollectionUtils.isEmpty(inventoryAvailableQtyList)) {
            return Maps.newHashMap();
        }

        return inventoryAvailableQtyList.stream()
                .collect(Collectors.toMap(p -> p.getWarehouseAreaId() + "_" + p.getGoodsId(), p -> p, (v1, v2) -> v1));
    }
}
